--Based on Conna's Breakable Props Tool
TOOL.Category    = "(WarMelons)"
TOOL.Name        = "#Contraption Legalizer"
TOOL.Command     = nil
TOOL.ConfigName  = ""

// Tables

local Breakable = {}

// ConVars

TOOL.ClientConVar["Attached"] = "1"
TOOL.ClientConVar["Use"] = "1"
TOOL.ClientConVar["Health"] = "100"
// Client

if (CLIENT) then
	language.Add("Tool_legalizer_name", "WarMelons Contraption Legalizer")
	language.Add("Tool_legalizer_desc", "Make an entity legal")
	language.Add("Tool_legalizer_0", "Click on an entity to make it breakable and Right click to repair it!")
	
	language.Add("Undone_legalizer", "Undone Breakable Prop")
end

// Message

function TOOL:Message(Text)
	if SERVER then
		self:GetOwner():SendLua("GAMEMODE:AddNotify('"..Text.."', NOTIFY_GENERIC, 10)")
		self:GetOwner():SendLua("surface.PlaySound('ambient/water/drip"..math.random(1, 4)..".wav')")
	end
end

// Get entities

local function ExtractEntities(Entity, Entities, Constraints)
	Constraints = Constraints or {}
	
	Entities = Entities or {}
	
	if (!Entity:IsValid()) then return Entities, Constraints end

	local Index = Entity:EntIndex()
	
	Entities[Index] = Entity
	
	if (!constraint.HasConstraints(Entity)) then return Entities, Constraints end
	
	local Cons = constraint.GetTable(Entity)
	
	for K, V in pairs(Cons) do
		local Index = V.Constraint
		
		if (!Constraints[Index]) then
			Constraints[Index] = V.Constraint
			
			for B, J in pairs(V.Entity) do
				local E, C = ExtractEntities(J.Entity, Entities, Constraints)
				
				table.Merge(Entities, E)
				table.Merge(Constraints, C)
			end
		end
	end
	
	return Entities, Constraints
end

// Left click

function TOOL:LeftClick(Trace)
local cost = 0
local ply = self:GetOwner()
local mteam = ply:GetNetworkedInt("melonteam")
	if (Trace.Entity) then
		if !Trace.Entity:IsValid() or Trace.Entity:IsPlayer() or Trace.HitWorld or Trace.Entity:IsNPC() then
			return false
		end
	end
	
	if(CLIENT) then
		return true
	end

	if(!SERVER) then return false end
	local Attached = self:GetClientNumber("Attached")
	local Health = self:GetClientNumber("Health")
	local Use = self:GetClientNumber("Use")
	local HP = 0
  if Use == 1 then
  HP = Health
  else
	HP       = math.floor(Trace.Entity:GetPhysicsObject():GetMass()*server_settings.Int( "WM_healthtomass", 2))
  end
	
	if (Attached == 1) then
		local Entities, Constraints = ExtractEntities(Trace.Entity)
			for K, V in pairs(Entities) do
			if V:IsValid() then
				if Use == 0 then
				local phys = V:GetPhysicsObject()
				if phys:IsValid() then
				local m = phys:GetMass()
					 if m < 750 then
					 cost = (cost + (m * server_settings.Int( "WM_propcost", 2)))
			         else
			         cost = (cost + (750 * server_settings.Int( "WM_propcost", 2)))
			         end
			         
			    end
			    else
			    cost = cost + (HP * server_settings.Int( "WM_propcost", 2))
			    end
			end
			end
			--1
	 if self:GetOwner():GetNetworkedInt("nrg") >= cost then
	 self:GetOwner():SetNetworkedInt("nrg", self:GetOwner():GetNetworkedInt("nrg") - cost )
	 self:GetOwner():PrintMessage(HUD_PRINTTALK, "Total cost: " .. cost .. " Your NRG: " .. self:GetOwner():GetNetworkedInt("nrg"))
		for K, V in pairs(Entities) do
			if V:IsValid() then
					if V:GetPhysicsObject():IsValid() then
					local m = V:GetPhysicsObject():GetMass()
					if Use == 0 then
					 if m < 750 then
					 HP = m * server_settings.Int( "WM_healthtomass", 2)
			         else
			         HP = 750 * server_settings.Int( "WM_healthtomass", 2)
			         end
			        else
			        HP = Health
			        end
			        end
					V.Breakable = {}
					
					V.Breakable.Cur = HP
					V.Breakable.Max = HP
         V.infot = ents.Create("info_target");
	       V.infot:SetPos(V:GetPos());
         V.infot:Spawn();
	       V.infot:Activate();
	       V.infot:SetParent(V);
	       V.infot.Warmelon = true;
	       V.infot.Team = ply:GetNetworkedInt("melonteam")
	       	if (mteam == 1) then
      		V:SetColor (255, 0, 0, 255);
      		end
      		if (mteam == 2) then
      		V:SetColor (0, 0, 255, 255);
      		end
      		if (mteam == 3) then
      		V:SetColor (0, 255, 0, 255);
      		end
      		if (mteam == 4) then
      		V:SetColor (255, 255, 0, 255);
      		end
      		if (mteam == 5) then
      		V:SetColor (255, 0, 255, 255);
      		end
      		if (mteam == 6) then
      		V:SetColor (0, 255, 255, 255);
      		end
					if (Wire_CreateOutputs) then
						V.Breakable.Outputs = Wire_CreateOutputs(V, {"Health", "Max"})
					end
					
					if (Wire_TriggerOutput) then
						Wire_TriggerOutput(V, "Health", HP)
						Wire_TriggerOutput(V, "Max", HP)
					end
					
					if (V:GetTable().OnTakeDamage) then
						local Prev = V:GetTable().OnTakeDamage
						
						function V:OnTakeDamage(Info)
							Breakable.DamagePhysicsEntity(self, Info:GetDamage())
							
							Prev(self, Info)
						end
					end
			end
		end
			else
	self:GetOwner():PrintMessage(HUD_PRINTTALK, "You don't have " .. cost .. " NRG.")
	end
	end
	return true
end

function TOOL:RightClick(Trace)
	local Attached = self:GetClientNumber("Attached")
	local Health = self:GetClientNumber("Health")
	local Use = self:GetClientNumber("Use")
	local HP = 0
	local cost = 0
	if (Attached == 1) then
		local Entities, Constraints = ExtractEntities(Trace.Entity)
			for K, V in pairs(Entities) do
			if V:IsValid() then
				if Use == 0 then
				local phys = V:GetPhysicsObject()
				if phys:IsValid() then
				local m = phys:GetMass()
					 if m < 750 then
					 cost = (cost + (m * server_settings.Int( "WM_propcost", 2)))
			         else
			         cost = (cost + (750 * server_settings.Int( "WM_propcost", 2)))
			         end
			         
			    end
			    else
			    cost = Health * server_settings.Int( "WM_propcost", 2)
			    end
			  end
			end
	end
self:GetOwner():PrintMessage(HUD_PRINTTALK, "Total cost:  " .. cost)
end

if SERVER then
	// Extinguish
	
	function Breakable.Extinguish(Entity)
		local HP = Entity.Breakable.Max
		
		Entity.Breakable.Cur = HP
		
		timer.Remove("Destroy:"..Entity:EntIndex())
		
		if (Entity:IsOnFire()) then
			Entity:Extinguish()
		end
		
		Breakable.DeleteEntityTrail(Entity)
		
		Entity:SetColor(255, 255, 255, 255)
		
		if (Wire_TriggerOutput) then
			Wire_TriggerOutput(Entity, "Health", HP)
			Wire_TriggerOutput(Entity, "Max", HP)
		end
	end
	
	// Delete entity trail
	
	function Breakable.DeleteEntityTrail(Entity)
		if (Entity.Breakable.Smoke and Entity.Breakable.Smoke:IsValid()) then
			Entity.Breakable.Smoke:Remove()
			
			Entity.Breakable.Smoke = nil
		end
	end
	
	// Set health based on color
	function Breakable.ColorHealthBased(Entity, HP, Col)
		if (Entity.Breakable.Cur <= (Entity.Breakable.Max / HP)) then
			Entity:SetColor(Col, Col, Col, 255)
		end
	end
	
	// Damage a physics entity
	
	function Breakable.DamagePhysicsEntity(Entity, Amount)
		Amount = math.floor(Amount / 2)
		
		if (Entity.Breakable and Entity.Breakable.Cur > 0) then
			local HP = Entity.Breakable.Cur - Amount
			
			Entity.Breakable.Cur = HP
			
			if (Entity.Breakable.Cur <= (Entity.Breakable.Max / 2)) then
				Breakable.CreateEntitySmokeTrail(Entity)
			end
			
			Breakable.ColorHealthBased(Entity, 2, 200)
			Breakable.ColorHealthBased(Entity, 3, 175)
			Breakable.ColorHealthBased(Entity, 4, 150)
			Breakable.ColorHealthBased(Entity, 5, 125)
			Breakable.ColorHealthBased(Entity, 6, 100)
			Breakable.ColorHealthBased(Entity, 7, 75)
			
			if (Entity.Breakable.Cur <= 0) then
				local function Func(Entity)
					if (Entity:IsValid()) then
						local Effect = EffectData()
							Effect:SetOrigin(Entity:GetPos())
							Effect:SetScale(1)
							Effect:SetMagnitude(25)
						util.Effect("Explosion", Effect, true, true)
						
						Entity:Remove()
					end
				end
				
				Entity:SetColor(50, 50, 50, 255)
				
				if not (Entity:IsOnFire()) then
					Entity:Ignite(30, 0)
				end
				
				timer.Create("Destroy:"..Entity:EntIndex(), 5, 1, Func, Entity)
			end
			
			if (Wire_TriggerOutput) then
				Wire_TriggerOutput(Entity, "Health", Entity.Breakable.Cur)
				Wire_TriggerOutput(Entity, "Max", Entity.Breakable.Max)
			end
		end
	end
	
	// Create smoke trail
	
	function Breakable.CreateEntitySmokeTrail(Entity)
		if not (Entity.Breakable.Smoke) then
			local Smoke = ents.Create("env_smoketrail")
			
			Smoke:SetKeyValue("opacity", 1)
			Smoke:SetKeyValue("spawnrate", 25)
			Smoke:SetKeyValue("lifetime", 2)
			Smoke:SetKeyValue("startcolor", "100 100 100")
			Smoke:SetKeyValue("endcolor", "125 125 125")
			Smoke:SetKeyValue("minspeed", 15)
			Smoke:SetKeyValue("maxspeed", 30)
			Smoke:SetKeyValue("startsize", (Entity:BoundingRadius() / 2))
			Smoke:SetKeyValue("endsize", Entity:BoundingRadius())
			Smoke:SetKeyValue("spawnradius", 10)
			Smoke:SetKeyValue("emittime", 300)
			Smoke:SetKeyValue("firesprite", "sprites/firetrail.spr")
			Smoke:SetKeyValue("smokesprite", "sprites/whitepuff.spr")
			Smoke:SetPos(Entity:GetPos())
			Smoke:SetParent(Entity)
			Smoke:Spawn()
			Smoke:Activate()
			
			// Delete on remove
			
			Entity:DeleteOnRemove(Smoke)
			
			// Networked variables
			
			Entity.Breakable.Smoke = Smoke
		end
	end
	
	// Entity take damage
	
	function TOOL.EntityTakeDamage(Entity, One, Two, Damage)
		Breakable.DamagePhysicsEntity(Entity, Damage)
	end
	
	hook.Add("EntityTakeDamage", "TOOL.EntityTakeDamage", TOOL.EntityTakeDamage)
end

// Build CPanel

function TOOL.BuildCPanel(Panel)
	Panel:AddControl("Header", {Text = "#Tool_legalizer_name", Description	= "#Tool_legalizer_desc"})

	Panel:AddControl("Checkbox", {Label = "#Make attached props breakable", Command = "legalizer_Attached"})
	
	Panel:AddControl("Checkbox", {Label = "#Use specified health", Command = "legalizer_Use"})

	Panel:AddControl("Slider", {Label = "#Health", Type	= "Integer", Min = 0, Max = 10000, Command = "legalizer_Health"})
end